├── .gitignore ├── .swiftlint.yml ├── .travis.yml ├── Cartfile ├── Cartfile.resolved ├── Demo ├── Demo.xcodeproj │ ├── project.pbxproj │ └── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── Demo │ ├── AppDelegate.swift │ ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ └── Contents.json │ └── Contents.json │ ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard │ ├── FirstViewController.swift │ ├── Info.plist │ └── SecondViewController.swift ├── LICENSE ├── README.md ├── Resources ├── Logo │ ├── StackBarButtonItem-Logo.ai │ └── logo.png └── Screenshot │ ├── Margin │ ├── margin_0.png │ └── margin_10.png │ ├── Reverse │ ├── reversed_false.png │ └── reversed_true.png │ └── Spacing │ ├── spacing_0.png │ └── spacing_10.png ├── StackBarButtonItem.podspec ├── StackBarButtonItem.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── xcshareddata │ └── xcschemes │ └── StackBarButtonItem-iOS.xcscheme ├── StackBarButtonItem.xcworkspace ├── contents.xcworkspacedata └── xcshareddata │ └── IDEWorkspaceChecks.plist ├── StackBarButtonItem ├── Resource │ └── Info-iOS.plist ├── Source │ ├── DeviceExtension.swift │ ├── StackBarButtonItem.swift │ ├── StackViewExtension.swift │ └── UINavigationItem+StackBarButtonItem.swift └── StackBarButtonItem.h ├── StackBarButtonItemTests ├── Info-iOS.plist └── StackBarButtonItemTests.swift └── codecov.yml /.gitignore: -------------------------------------------------------------------------------- 1 | ### https://raw.github.com/github/gitignore/766e2a1f6276219fed1f18f11508261adbcb8257/Swift.gitignore 2 | 3 | # Xcode 4 | # 5 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 6 | 7 | ## Build generated 8 | build/ 9 | DerivedData/ 10 | 11 | ## Various settings 12 | *.pbxuser 13 | !default.pbxuser 14 | *.mode1v3 15 | !default.mode1v3 16 | *.mode2v3 17 | !default.mode2v3 18 | *.perspectivev3 19 | !default.perspectivev3 20 | xcuserdata/ 21 | 22 | ## Other 23 | *.moved-aside 24 | *.xccheckout 25 | *.xcscmblueprint 26 | 27 | ## Obj-C/Swift specific 28 | *.hmap 29 | *.ipa 30 | *.dSYM.zip 31 | *.dSYM 32 | 33 | ## Playgrounds 34 | timeline.xctimeline 35 | playground.xcworkspace 36 | 37 | # Swift Package Manager 38 | # 39 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 40 | # Packages/ 41 | # Package.pins 42 | # Package.resolved 43 | .build/ 44 | 45 | # CocoaPods 46 | # 47 | # We recommend against adding the Pods directory to your .gitignore. However 48 | # you should judge for yourself, the pros and cons are mentioned at: 49 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 50 | # 51 | # Pods/ 52 | 53 | # Carthage 54 | # 55 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 56 | Carthage/Checkouts 57 | Carthage/Build 58 | 59 | # fastlane 60 | # 61 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 62 | # screenshots whenever they are needed. 63 | # For more information about the recommended setup visit: 64 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 65 | 66 | fastlane/report.xml 67 | fastlane/Preview.html 68 | fastlane/screenshots/**/*.png 69 | fastlane/test_output 70 | 71 | 72 | -------------------------------------------------------------------------------- /.swiftlint.yml: -------------------------------------------------------------------------------- 1 | excluded: 2 | - Pods/ 3 | - Demo/ 4 | - Carthage/ 5 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: objective-c 2 | osx_image: xcode10.3 3 | xcode_workspace: StackBarButtonItem.xcworkspace 4 | xcode_scheme: StackBarButtonItem-iOS 5 | xcode_sdk: iphonesimulator 6 | before_install: 7 | - gem install xcpretty 8 | - gem install cocoapods --pre 9 | - pod repo update 10 | - brew update 11 | - carthage update --no-use-binaries --platform iOS 12 | before_script: 13 | - set -o pipefail 14 | script: 15 | - xcodebuild test -workspace StackBarButtonItem.xcworkspace -scheme StackBarButtonItem-iOS -configuration Debug -sdk iphonesimulator -destination 'platform=iOS Simulator,OS=12.0,name=iPhone X'| xcpretty -c 16 | - pod lib lint 17 | after_success: 18 | - bash <(curl -s https://codecov.io/bash) 19 | notifications: 20 | email: false 21 | -------------------------------------------------------------------------------- /Cartfile: -------------------------------------------------------------------------------- 1 | github "ReactiveX/RxSwift" ~> 5.0.0 2 | -------------------------------------------------------------------------------- /Cartfile.resolved: -------------------------------------------------------------------------------- 1 | github "ReactiveX/RxSwift" "5.0.1" 2 | -------------------------------------------------------------------------------- /Demo/Demo.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 311A842F2144A88B007517A1 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 311A842E2144A88B007517A1 /* AppDelegate.swift */; }; 11 | 311A84312144A88B007517A1 /* FirstViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 311A84302144A88B007517A1 /* FirstViewController.swift */; }; 12 | 311A84342144A88B007517A1 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 311A84322144A88B007517A1 /* Main.storyboard */; }; 13 | 311A84362144A88D007517A1 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 311A84352144A88D007517A1 /* Assets.xcassets */; }; 14 | 311A84392144A88D007517A1 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 311A84372144A88D007517A1 /* LaunchScreen.storyboard */; }; 15 | 311A84482144A90E007517A1 /* StackBarButtonItem.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 311A84472144A90E007517A1 /* StackBarButtonItem.framework */; }; 16 | 31594FCD2176E06800F3E040 /* SecondViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31594FCC2176E06800F3E040 /* SecondViewController.swift */; }; 17 | /* End PBXBuildFile section */ 18 | 19 | /* Begin PBXFileReference section */ 20 | 311A842B2144A88B007517A1 /* Demo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Demo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 21 | 311A842E2144A88B007517A1 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 22 | 311A84302144A88B007517A1 /* FirstViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FirstViewController.swift; sourceTree = ""; }; 23 | 311A84332144A88B007517A1 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 24 | 311A84352144A88D007517A1 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 25 | 311A84382144A88D007517A1 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 26 | 311A843A2144A88D007517A1 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 27 | 311A84472144A90E007517A1 /* StackBarButtonItem.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = StackBarButtonItem.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 28 | 31594FCC2176E06800F3E040 /* SecondViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecondViewController.swift; sourceTree = ""; }; 29 | /* End PBXFileReference section */ 30 | 31 | /* Begin PBXFrameworksBuildPhase section */ 32 | 311A84282144A88B007517A1 /* Frameworks */ = { 33 | isa = PBXFrameworksBuildPhase; 34 | buildActionMask = 2147483647; 35 | files = ( 36 | 311A84482144A90E007517A1 /* StackBarButtonItem.framework in Frameworks */, 37 | ); 38 | runOnlyForDeploymentPostprocessing = 0; 39 | }; 40 | /* End PBXFrameworksBuildPhase section */ 41 | 42 | /* Begin PBXGroup section */ 43 | 311A84222144A88B007517A1 = { 44 | isa = PBXGroup; 45 | children = ( 46 | 311A842D2144A88B007517A1 /* Demo */, 47 | 311A842C2144A88B007517A1 /* Products */, 48 | 311A84462144A90E007517A1 /* Frameworks */, 49 | ); 50 | sourceTree = ""; 51 | }; 52 | 311A842C2144A88B007517A1 /* Products */ = { 53 | isa = PBXGroup; 54 | children = ( 55 | 311A842B2144A88B007517A1 /* Demo.app */, 56 | ); 57 | name = Products; 58 | sourceTree = ""; 59 | }; 60 | 311A842D2144A88B007517A1 /* Demo */ = { 61 | isa = PBXGroup; 62 | children = ( 63 | 311A842E2144A88B007517A1 /* AppDelegate.swift */, 64 | 311A84302144A88B007517A1 /* FirstViewController.swift */, 65 | 31594FCC2176E06800F3E040 /* SecondViewController.swift */, 66 | 311A84322144A88B007517A1 /* Main.storyboard */, 67 | 311A84352144A88D007517A1 /* Assets.xcassets */, 68 | 311A84372144A88D007517A1 /* LaunchScreen.storyboard */, 69 | 311A843A2144A88D007517A1 /* Info.plist */, 70 | ); 71 | path = Demo; 72 | sourceTree = ""; 73 | }; 74 | 311A84462144A90E007517A1 /* Frameworks */ = { 75 | isa = PBXGroup; 76 | children = ( 77 | 311A84472144A90E007517A1 /* StackBarButtonItem.framework */, 78 | ); 79 | name = Frameworks; 80 | sourceTree = ""; 81 | }; 82 | /* End PBXGroup section */ 83 | 84 | /* Begin PBXNativeTarget section */ 85 | 311A842A2144A88B007517A1 /* Demo */ = { 86 | isa = PBXNativeTarget; 87 | buildConfigurationList = 311A843D2144A88D007517A1 /* Build configuration list for PBXNativeTarget "Demo" */; 88 | buildPhases = ( 89 | 311A84272144A88B007517A1 /* Sources */, 90 | 311A84282144A88B007517A1 /* Frameworks */, 91 | 311A84292144A88B007517A1 /* Resources */, 92 | 31E7EE2121455B8B00969E92 /* ShellScript */, 93 | ); 94 | buildRules = ( 95 | ); 96 | dependencies = ( 97 | ); 98 | name = Demo; 99 | productName = Demo; 100 | productReference = 311A842B2144A88B007517A1 /* Demo.app */; 101 | productType = "com.apple.product-type.application"; 102 | }; 103 | /* End PBXNativeTarget section */ 104 | 105 | /* Begin PBXProject section */ 106 | 311A84232144A88B007517A1 /* Project object */ = { 107 | isa = PBXProject; 108 | attributes = { 109 | LastSwiftUpdateCheck = 0940; 110 | LastUpgradeCheck = 0940; 111 | ORGANIZATIONNAME = "中澤郁斗"; 112 | TargetAttributes = { 113 | 311A842A2144A88B007517A1 = { 114 | CreatedOnToolsVersion = 9.4.1; 115 | }; 116 | }; 117 | }; 118 | buildConfigurationList = 311A84262144A88B007517A1 /* Build configuration list for PBXProject "Demo" */; 119 | compatibilityVersion = "Xcode 9.3"; 120 | developmentRegion = en; 121 | hasScannedForEncodings = 0; 122 | knownRegions = ( 123 | en, 124 | Base, 125 | ); 126 | mainGroup = 311A84222144A88B007517A1; 127 | productRefGroup = 311A842C2144A88B007517A1 /* Products */; 128 | projectDirPath = ""; 129 | projectRoot = ""; 130 | targets = ( 131 | 311A842A2144A88B007517A1 /* Demo */, 132 | ); 133 | }; 134 | /* End PBXProject section */ 135 | 136 | /* Begin PBXResourcesBuildPhase section */ 137 | 311A84292144A88B007517A1 /* Resources */ = { 138 | isa = PBXResourcesBuildPhase; 139 | buildActionMask = 2147483647; 140 | files = ( 141 | 311A84392144A88D007517A1 /* LaunchScreen.storyboard in Resources */, 142 | 311A84362144A88D007517A1 /* Assets.xcassets in Resources */, 143 | 311A84342144A88B007517A1 /* Main.storyboard in Resources */, 144 | ); 145 | runOnlyForDeploymentPostprocessing = 0; 146 | }; 147 | /* End PBXResourcesBuildPhase section */ 148 | 149 | /* Begin PBXShellScriptBuildPhase section */ 150 | 31E7EE2121455B8B00969E92 /* ShellScript */ = { 151 | isa = PBXShellScriptBuildPhase; 152 | buildActionMask = 2147483647; 153 | files = ( 154 | ); 155 | inputPaths = ( 156 | ); 157 | outputPaths = ( 158 | ); 159 | runOnlyForDeploymentPostprocessing = 0; 160 | shellPath = /bin/sh; 161 | shellScript = "# Type a script or drag a script file from your workspace to insert its path.\n"; 162 | }; 163 | /* End PBXShellScriptBuildPhase section */ 164 | 165 | /* Begin PBXSourcesBuildPhase section */ 166 | 311A84272144A88B007517A1 /* Sources */ = { 167 | isa = PBXSourcesBuildPhase; 168 | buildActionMask = 2147483647; 169 | files = ( 170 | 31594FCD2176E06800F3E040 /* SecondViewController.swift in Sources */, 171 | 311A84312144A88B007517A1 /* FirstViewController.swift in Sources */, 172 | 311A842F2144A88B007517A1 /* AppDelegate.swift in Sources */, 173 | ); 174 | runOnlyForDeploymentPostprocessing = 0; 175 | }; 176 | /* End PBXSourcesBuildPhase section */ 177 | 178 | /* Begin PBXVariantGroup section */ 179 | 311A84322144A88B007517A1 /* Main.storyboard */ = { 180 | isa = PBXVariantGroup; 181 | children = ( 182 | 311A84332144A88B007517A1 /* Base */, 183 | ); 184 | name = Main.storyboard; 185 | sourceTree = ""; 186 | }; 187 | 311A84372144A88D007517A1 /* LaunchScreen.storyboard */ = { 188 | isa = PBXVariantGroup; 189 | children = ( 190 | 311A84382144A88D007517A1 /* Base */, 191 | ); 192 | name = LaunchScreen.storyboard; 193 | sourceTree = ""; 194 | }; 195 | /* End PBXVariantGroup section */ 196 | 197 | /* Begin XCBuildConfiguration section */ 198 | 311A843B2144A88D007517A1 /* Debug */ = { 199 | isa = XCBuildConfiguration; 200 | buildSettings = { 201 | ALWAYS_SEARCH_USER_PATHS = NO; 202 | CLANG_ANALYZER_NONNULL = YES; 203 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 204 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 205 | CLANG_CXX_LIBRARY = "libc++"; 206 | CLANG_ENABLE_MODULES = YES; 207 | CLANG_ENABLE_OBJC_ARC = YES; 208 | CLANG_ENABLE_OBJC_WEAK = YES; 209 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 210 | CLANG_WARN_BOOL_CONVERSION = YES; 211 | CLANG_WARN_COMMA = YES; 212 | CLANG_WARN_CONSTANT_CONVERSION = YES; 213 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 214 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 215 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 216 | CLANG_WARN_EMPTY_BODY = YES; 217 | CLANG_WARN_ENUM_CONVERSION = YES; 218 | CLANG_WARN_INFINITE_RECURSION = YES; 219 | CLANG_WARN_INT_CONVERSION = YES; 220 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 221 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 222 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 223 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 224 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 225 | CLANG_WARN_STRICT_PROTOTYPES = YES; 226 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 227 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 228 | CLANG_WARN_UNREACHABLE_CODE = YES; 229 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 230 | CODE_SIGN_IDENTITY = "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 = gnu11; 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 = 11.4; 250 | MTL_ENABLE_DEBUG_INFO = YES; 251 | ONLY_ACTIVE_ARCH = YES; 252 | SDKROOT = iphoneos; 253 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 254 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 255 | }; 256 | name = Debug; 257 | }; 258 | 311A843C2144A88D007517A1 /* Release */ = { 259 | isa = XCBuildConfiguration; 260 | buildSettings = { 261 | ALWAYS_SEARCH_USER_PATHS = NO; 262 | CLANG_ANALYZER_NONNULL = YES; 263 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 264 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 265 | CLANG_CXX_LIBRARY = "libc++"; 266 | CLANG_ENABLE_MODULES = YES; 267 | CLANG_ENABLE_OBJC_ARC = YES; 268 | CLANG_ENABLE_OBJC_WEAK = YES; 269 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 270 | CLANG_WARN_BOOL_CONVERSION = YES; 271 | CLANG_WARN_COMMA = YES; 272 | CLANG_WARN_CONSTANT_CONVERSION = YES; 273 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 274 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 275 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 276 | CLANG_WARN_EMPTY_BODY = YES; 277 | CLANG_WARN_ENUM_CONVERSION = YES; 278 | CLANG_WARN_INFINITE_RECURSION = YES; 279 | CLANG_WARN_INT_CONVERSION = YES; 280 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 281 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 282 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 283 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 284 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 285 | CLANG_WARN_STRICT_PROTOTYPES = YES; 286 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 287 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 288 | CLANG_WARN_UNREACHABLE_CODE = YES; 289 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 290 | CODE_SIGN_IDENTITY = "iPhone Developer"; 291 | COPY_PHASE_STRIP = NO; 292 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 293 | ENABLE_NS_ASSERTIONS = NO; 294 | ENABLE_STRICT_OBJC_MSGSEND = YES; 295 | GCC_C_LANGUAGE_STANDARD = gnu11; 296 | GCC_NO_COMMON_BLOCKS = YES; 297 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 298 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 299 | GCC_WARN_UNDECLARED_SELECTOR = YES; 300 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 301 | GCC_WARN_UNUSED_FUNCTION = YES; 302 | GCC_WARN_UNUSED_VARIABLE = YES; 303 | IPHONEOS_DEPLOYMENT_TARGET = 11.4; 304 | MTL_ENABLE_DEBUG_INFO = NO; 305 | SDKROOT = iphoneos; 306 | SWIFT_COMPILATION_MODE = wholemodule; 307 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 308 | VALIDATE_PRODUCT = YES; 309 | }; 310 | name = Release; 311 | }; 312 | 311A843E2144A88D007517A1 /* Debug */ = { 313 | isa = XCBuildConfiguration; 314 | buildSettings = { 315 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 316 | CODE_SIGN_STYLE = Manual; 317 | DEVELOPMENT_TEAM = ""; 318 | INFOPLIST_FILE = Demo/Info.plist; 319 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 320 | LD_RUNPATH_SEARCH_PATHS = ( 321 | "$(inherited)", 322 | "@executable_path/Frameworks", 323 | ); 324 | PRODUCT_BUNDLE_IDENTIFIER = com.funzin.Demo; 325 | PRODUCT_NAME = "$(TARGET_NAME)"; 326 | PROVISIONING_PROFILE_SPECIFIER = ""; 327 | SWIFT_VERSION = 5.0; 328 | TARGETED_DEVICE_FAMILY = "1,2"; 329 | }; 330 | name = Debug; 331 | }; 332 | 311A843F2144A88D007517A1 /* Release */ = { 333 | isa = XCBuildConfiguration; 334 | buildSettings = { 335 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 336 | CODE_SIGN_STYLE = Manual; 337 | DEVELOPMENT_TEAM = ""; 338 | INFOPLIST_FILE = Demo/Info.plist; 339 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 340 | LD_RUNPATH_SEARCH_PATHS = ( 341 | "$(inherited)", 342 | "@executable_path/Frameworks", 343 | ); 344 | PRODUCT_BUNDLE_IDENTIFIER = com.funzin.Demo; 345 | PRODUCT_NAME = "$(TARGET_NAME)"; 346 | PROVISIONING_PROFILE_SPECIFIER = ""; 347 | SWIFT_VERSION = 5.0; 348 | TARGETED_DEVICE_FAMILY = "1,2"; 349 | }; 350 | name = Release; 351 | }; 352 | /* End XCBuildConfiguration section */ 353 | 354 | /* Begin XCConfigurationList section */ 355 | 311A84262144A88B007517A1 /* Build configuration list for PBXProject "Demo" */ = { 356 | isa = XCConfigurationList; 357 | buildConfigurations = ( 358 | 311A843B2144A88D007517A1 /* Debug */, 359 | 311A843C2144A88D007517A1 /* Release */, 360 | ); 361 | defaultConfigurationIsVisible = 0; 362 | defaultConfigurationName = Release; 363 | }; 364 | 311A843D2144A88D007517A1 /* Build configuration list for PBXNativeTarget "Demo" */ = { 365 | isa = XCConfigurationList; 366 | buildConfigurations = ( 367 | 311A843E2144A88D007517A1 /* Debug */, 368 | 311A843F2144A88D007517A1 /* Release */, 369 | ); 370 | defaultConfigurationIsVisible = 0; 371 | defaultConfigurationName = Release; 372 | }; 373 | /* End XCConfigurationList section */ 374 | }; 375 | rootObject = 311A84232144A88B007517A1 /* Project object */; 376 | } 377 | -------------------------------------------------------------------------------- /Demo/Demo.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Demo/Demo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Demo/Demo/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | @UIApplicationMain 4 | class AppDelegate: UIResponder, UIApplicationDelegate { 5 | 6 | var window: UIWindow? 7 | 8 | 9 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 10 | // Override point for customization after application launch. 11 | return true 12 | } 13 | 14 | func applicationWillResignActive(_ application: UIApplication) { 15 | // 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. 16 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 17 | } 18 | 19 | func applicationDidEnterBackground(_ application: UIApplication) { 20 | // 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. 21 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 22 | } 23 | 24 | func applicationWillEnterForeground(_ application: UIApplication) { 25 | // 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. 26 | } 27 | 28 | func applicationDidBecomeActive(_ application: UIApplication) { 29 | // 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. 30 | } 31 | 32 | func applicationWillTerminate(_ application: UIApplication) { 33 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 34 | } 35 | 36 | 37 | } 38 | 39 | -------------------------------------------------------------------------------- /Demo/Demo/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "size" : "1024x1024", 91 | "scale" : "1x" 92 | } 93 | ], 94 | "info" : { 95 | "version" : 1, 96 | "author" : "xcode" 97 | } 98 | } -------------------------------------------------------------------------------- /Demo/Demo/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Demo/Demo/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 | -------------------------------------------------------------------------------- /Demo/Demo/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 | 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 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /Demo/Demo/FirstViewController.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import StackBarButtonItem 3 | 4 | class FirstViewController: UIViewController { 5 | 6 | private var rightButton1: UIButton! { 7 | didSet { 8 | rightButton1.setTitle("right1", for: .normal) 9 | rightButton1.titleLabel!.font = UIFont.systemFont(ofSize: 14) 10 | rightButton1.setTitleColor(.white, for: .normal) 11 | rightButton1.backgroundColor = .blue 12 | rightButton1.addTarget(self, action: #selector(self.pushToSecondVC), for: .touchUpInside) 13 | } 14 | } 15 | 16 | private var rightButton2: UIButton! { 17 | didSet { 18 | rightButton2.setTitle("right2", for: .normal) 19 | rightButton2.titleLabel!.font = UIFont.systemFont(ofSize: 14) 20 | rightButton2.setTitleColor(.white, for: .normal) 21 | rightButton2.backgroundColor = .red 22 | } 23 | } 24 | 25 | private var leftButton: UIButton! { 26 | didSet { 27 | leftButton.setTitle("left", for: .normal) 28 | leftButton.titleLabel!.font = UIFont.systemFont(ofSize: 14) 29 | leftButton.setTitleColor(.white, for: .normal) 30 | leftButton.backgroundColor = .purple 31 | leftButton.addTarget(self, action: #selector(self.pushToSecondVC), for: .touchUpInside) 32 | } 33 | } 34 | 35 | override func viewDidLoad() { 36 | super.viewDidLoad() 37 | let navigationHeight = self.navigationController!.navigationBar.frame.height 38 | 39 | RightButton: do { 40 | rightButton1 = UIButton(frame: CGRect(x: 0, y: 0, width: 44, height: navigationHeight)) 41 | rightButton2 = UIButton(frame: CGRect(x: 0, y: 0, width: 44, height: navigationHeight)) 42 | NSLayoutConstraint.activate([ 43 | rightButton1.widthAnchor.constraint(equalToConstant: 44), 44 | rightButton1.heightAnchor.constraint(equalToConstant: 44), 45 | rightButton2.widthAnchor.constraint(equalToConstant: 44), 46 | rightButton2.heightAnchor.constraint(equalToConstant: 44), 47 | ]) 48 | 49 | self.navigationItem.right.setStackBarButtonItems(views: [rightButton1, rightButton2]) 50 | } 51 | 52 | LeftButton: do { 53 | leftButton = UIButton(frame: CGRect(x: 0, y: 0, width: 44, height: navigationHeight)) 54 | NSLayoutConstraint.activate([ 55 | leftButton.widthAnchor.constraint(equalToConstant: 44), 56 | leftButton.heightAnchor.constraint(equalToConstant: 44) 57 | ]) 58 | 59 | self.navigationItem.left.setStackBarButtonItems(views: [leftButton]) 60 | } 61 | } 62 | 63 | @objc func pushToSecondVC() { 64 | performSegue(withIdentifier: "second", sender: nil) 65 | } 66 | } 67 | 68 | -------------------------------------------------------------------------------- /Demo/Demo/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationLandscapeLeft 34 | UIInterfaceOrientationLandscapeRight 35 | UIInterfaceOrientationPortrait 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /Demo/Demo/SecondViewController.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | class SecondViewController: UIViewController { 4 | override func viewDidLoad() { 5 | super.viewDidLoad() 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Fumito Nakazawa 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # StackBarButtonItem 2 |

3 | StackBarButtonItem 4 |

5 | 6 |

7 | 8 | 9 | 10 | 11 | 12 | 13 | Platform 14 | 15 | Language 16 | 17 | 18 | Carthage 19 | 20 | 21 | Version 22 | 23 | 24 | License 25 | 26 |

27 | 28 | StackBarButtonItem can use BarButtonItem like stackView. 29 | 30 | 31 | ## Features 32 | - NavigationBar margin 33 | - Spacing between view 34 | - Reverse view 35 | 36 | ## Support 37 | - Device: iPad | iPhone 38 | - Orientation: Portrait | Landscape 39 | - Multitasking 40 | 41 | ## Requirements 42 | - Xcode10 or greater 43 | - iOS9 or greater 44 | - Swift4.2 or greater 45 | 46 | ## Dependencies 47 | - [RxSwift](https://github.com/ReactiveX/RxSwift) (>= 4.3.1) 48 | - [RxCocoa](https://github.com/ReactiveX/RxSwift/tree/master/RxCocoa) (>= 4.3.1) 49 | 50 | ## Installation 51 | ### Carthage 52 | 53 | If you’re using [Carthage](https://github.com/Carthage/Carthage), simply add 54 | StackBarButtonItem to your `Cartfile`: 55 | 56 | ```ruby 57 | github "funzin/StackBarButtonItem" 58 | ``` 59 | 60 | ### CocoaPods 61 | StackBarButtonItem is available through [CocoaPods](https://cocoapods.org). To instal 62 | it, simply add the following line to your Podfile: 63 | 64 | ```ruby 65 | pod 'StackBarButtonItem' 66 | ``` 67 | 68 | ## Usage 69 | ### Correspondence Table 70 | |position|Default|StackBarButtonItem| 71 | |:-:|:-:|:-:| 72 | |right|`navigationItem.setRightBarButtonItems`|`navigationItem.right.setStackBarButtonItems`| 73 | |left|`navigationItem.setLeftBarButtonItems`|`navigationItem.left.setStackBarButtonItems`| 74 | 75 | ### Introduction 76 | #### iOS11 or later 77 | If iOS version is iOS11 or later, you must use autolayout. 78 | ```swift 79 | import StackBarButtonItem 80 | ・ 81 | ・ 82 | ・ 83 | 84 | // use autolayout 85 | let rightButton = UIButton(frame: CGRect(x: 0, y: 0, width: 44, height: 44)) 86 | NSLayoutConstraint.activate([ 87 | rightButton.widthAnchor.constraint(equalToConstant: 44), 88 | rightButton.heightAnchor.constraint(equalToConstant: 44) 89 | ]) 90 | self.navigationItem.right.setStackBarButtonItems(views: [rightButton]) 91 | ``` 92 | 93 | #### iOS9 or iOS10 94 | If iOS version is iOS9 or iOS10, you must configure frame. 95 | ```swift 96 | import StackBarButtonItem 97 | ・ 98 | ・ 99 | ・ 100 | 101 | // configure frame 102 | let rightButton = UIButton(frame: CGRect(x: 0, y: 0, width: 44, height: 44)) 103 | self.navigationItem.right.setStackBarButtonItems(views: [rightButton]) 104 | ``` 105 | 106 | ### Margin 107 | ```swift 108 | // e.g. set margin to 10 109 | self.navigationItem.right.setStackBarButtonItems(views: [rightButton], margin: 10) 110 | ``` 111 | 112 | #### Example 113 | |Margin|ScreenShot| 114 | |:-:|:-:| 115 | |`margin == 0`|| 116 | |`margin == 10`|| 117 | 118 | ### Spacing 119 | ```swift 120 | // e.g. set spacing to 10 121 | self.navigationItem.right.setStackBarButtonItems(views: [rightButton1, rightButton2], spacing: 10) 122 | ``` 123 | 124 | #### Example 125 | |Spacing|ScreenShot| 126 | |:-:|:-:| 127 | |`spacing == 0`|| 128 | |`spacing == 10`|| 129 | 130 | ### Reverse 131 | ```swift 132 | // e.g. set reversed to true 133 | self.navigationItem.right.setStackBarButtonItems(views: [rightButton1, rightButton2], reversed: true) 134 | ``` 135 | 136 | #### Example 137 | |Reverse|ScreenShot| 138 | |:-:|:-:| 139 | |`reversed == false`|| 140 | |`reversed == true`|| 141 | 142 | ## Demo 143 | If you are interested in StackBarButtonItem, please check demo after `carthage update` 144 | 145 | ## Author 146 | funzin, nakazawa.fumito@gmail.com 147 | ## License 148 | StackBarButtonItem is available under the MIT license. See the [LICENSE file](https://github.com/funzin/StackBarButtonItem/blob/master/LICENSE) for more info. 149 | -------------------------------------------------------------------------------- /Resources/Logo/StackBarButtonItem-Logo.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/funzin/StackBarButtonItem/54bca410d3a7707baa38bd62b3c322a876e22bfe/Resources/Logo/StackBarButtonItem-Logo.ai -------------------------------------------------------------------------------- /Resources/Logo/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/funzin/StackBarButtonItem/54bca410d3a7707baa38bd62b3c322a876e22bfe/Resources/Logo/logo.png -------------------------------------------------------------------------------- /Resources/Screenshot/Margin/margin_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/funzin/StackBarButtonItem/54bca410d3a7707baa38bd62b3c322a876e22bfe/Resources/Screenshot/Margin/margin_0.png -------------------------------------------------------------------------------- /Resources/Screenshot/Margin/margin_10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/funzin/StackBarButtonItem/54bca410d3a7707baa38bd62b3c322a876e22bfe/Resources/Screenshot/Margin/margin_10.png -------------------------------------------------------------------------------- /Resources/Screenshot/Reverse/reversed_false.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/funzin/StackBarButtonItem/54bca410d3a7707baa38bd62b3c322a876e22bfe/Resources/Screenshot/Reverse/reversed_false.png -------------------------------------------------------------------------------- /Resources/Screenshot/Reverse/reversed_true.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/funzin/StackBarButtonItem/54bca410d3a7707baa38bd62b3c322a876e22bfe/Resources/Screenshot/Reverse/reversed_true.png -------------------------------------------------------------------------------- /Resources/Screenshot/Spacing/spacing_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/funzin/StackBarButtonItem/54bca410d3a7707baa38bd62b3c322a876e22bfe/Resources/Screenshot/Spacing/spacing_0.png -------------------------------------------------------------------------------- /Resources/Screenshot/Spacing/spacing_10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/funzin/StackBarButtonItem/54bca410d3a7707baa38bd62b3c322a876e22bfe/Resources/Screenshot/Spacing/spacing_10.png -------------------------------------------------------------------------------- /StackBarButtonItem.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "StackBarButtonItem" 3 | s.version = "0.1.1" 4 | s.summary = "StackBarButtonItem can use BarButtonItem like stackView." 5 | s.homepage = "https://github.com/funzin/StackBarButtonItem" 6 | s.license = { :type => "MIT", :file => "LICENSE" } 7 | s.author = { "funzin" => "nakazawa.fumito@gmail.com" } 8 | s.ios.deployment_target = "9.0" 9 | s.source = { :git => "https://github.com/funzin/StackBarButtonItem.git", :tag => "#{s.version}" } 10 | s.source_files = "StackBarButtonItem/**/*.{swift}" 11 | 12 | s.dependency "RxSwift", "~> 5.0.0" 13 | s.dependency "RxCocoa", "~> 5.0.0" 14 | s.swift_version = '5.0' 15 | end 16 | -------------------------------------------------------------------------------- /StackBarButtonItem.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 313C7CF0217B7660003B50D1 /* StackViewExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 313C7CEF217B7660003B50D1 /* StackViewExtension.swift */; }; 11 | 314AF93E2146666C0008202E /* StackBarButtonItem.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D4EC7A6D2136B8AE0034767C /* StackBarButtonItem.framework */; }; 12 | 314AF962214666F70008202E /* StackBarButtonItemTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4EC7A502136B7EE0034767C /* StackBarButtonItemTests.swift */; }; 13 | 314AF9662146783F0008202E /* DeviceExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 314AF9652146783F0008202E /* DeviceExtension.swift */; }; 14 | 31658C74217B0AEF00FD3E18 /* UINavigationItem+StackBarButtonItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31658C73217B0AEF00FD3E18 /* UINavigationItem+StackBarButtonItem.swift */; }; 15 | 3176E4C1230541DA00CB14B0 /* RxCocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D4EC7A992136BC5C0034767C /* RxCocoa.framework */; }; 16 | 3176E4C2230541DA00CB14B0 /* RxRelay.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3176E4BC2305411300CB14B0 /* RxRelay.framework */; }; 17 | 3176E4C3230541DA00CB14B0 /* RxSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D4EC7A9B2136BC5C0034767C /* RxSwift.framework */; }; 18 | D4EC7A912136BA8F0034767C /* StackBarButtonItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4EC7A5E2136B8070034767C /* StackBarButtonItem.swift */; }; 19 | /* End PBXBuildFile section */ 20 | 21 | /* Begin PBXContainerItemProxy section */ 22 | 314AF93F2146666C0008202E /* PBXContainerItemProxy */ = { 23 | isa = PBXContainerItemProxy; 24 | containerPortal = D4EC7A392136B7EE0034767C /* Project object */; 25 | proxyType = 1; 26 | remoteGlobalIDString = D4EC7A6C2136B8AE0034767C; 27 | remoteInfo = "StackBarButtonItem-iOS"; 28 | }; 29 | /* End PBXContainerItemProxy section */ 30 | 31 | /* Begin PBXFileReference section */ 32 | 313C7CEF217B7660003B50D1 /* StackViewExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StackViewExtension.swift; sourceTree = ""; }; 33 | 314AF92F214665D60008202E /* Info-iOS.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "Info-iOS.plist"; sourceTree = ""; }; 34 | 314AF9392146666B0008202E /* StackBarButtonItemTests-iOS.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "StackBarButtonItemTests-iOS.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 35 | 314AF9652146783F0008202E /* DeviceExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceExtension.swift; sourceTree = ""; }; 36 | 31658C73217B0AEF00FD3E18 /* UINavigationItem+StackBarButtonItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UINavigationItem+StackBarButtonItem.swift"; sourceTree = ""; }; 37 | 3176E4BC2305411300CB14B0 /* RxRelay.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = RxRelay.framework; path = Carthage/Build/iOS/RxRelay.framework; sourceTree = ""; }; 38 | D4EC7A452136B7EE0034767C /* StackBarButtonItem.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = StackBarButtonItem.h; sourceTree = ""; }; 39 | D4EC7A502136B7EE0034767C /* StackBarButtonItemTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StackBarButtonItemTests.swift; sourceTree = ""; }; 40 | D4EC7A5E2136B8070034767C /* StackBarButtonItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StackBarButtonItem.swift; sourceTree = ""; }; 41 | D4EC7A632136B8100034767C /* Info-iOS.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "Info-iOS.plist"; sourceTree = ""; }; 42 | D4EC7A6D2136B8AE0034767C /* StackBarButtonItem.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = StackBarButtonItem.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 43 | D4EC7A972136BC5C0034767C /* NSObject_Rx.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = NSObject_Rx.framework; path = Carthage/Build/iOS/NSObject_Rx.framework; sourceTree = ""; }; 44 | D4EC7A982136BC5C0034767C /* RxBlocking.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = RxBlocking.framework; path = Carthage/Build/iOS/RxBlocking.framework; sourceTree = ""; }; 45 | D4EC7A992136BC5C0034767C /* RxCocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = RxCocoa.framework; path = Carthage/Build/iOS/RxCocoa.framework; sourceTree = ""; }; 46 | D4EC7A9A2136BC5C0034767C /* RxTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = RxTest.framework; path = Carthage/Build/iOS/RxTest.framework; sourceTree = ""; }; 47 | D4EC7A9B2136BC5C0034767C /* RxSwift.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = RxSwift.framework; path = Carthage/Build/iOS/RxSwift.framework; sourceTree = ""; }; 48 | /* End PBXFileReference section */ 49 | 50 | /* Begin PBXFrameworksBuildPhase section */ 51 | 314AF9362146666B0008202E /* Frameworks */ = { 52 | isa = PBXFrameworksBuildPhase; 53 | buildActionMask = 2147483647; 54 | files = ( 55 | 314AF93E2146666C0008202E /* StackBarButtonItem.framework in Frameworks */, 56 | ); 57 | runOnlyForDeploymentPostprocessing = 0; 58 | }; 59 | D4EC7A692136B8AE0034767C /* Frameworks */ = { 60 | isa = PBXFrameworksBuildPhase; 61 | buildActionMask = 2147483647; 62 | files = ( 63 | 3176E4C1230541DA00CB14B0 /* RxCocoa.framework in Frameworks */, 64 | 3176E4C2230541DA00CB14B0 /* RxRelay.framework in Frameworks */, 65 | 3176E4C3230541DA00CB14B0 /* RxSwift.framework in Frameworks */, 66 | ); 67 | runOnlyForDeploymentPostprocessing = 0; 68 | }; 69 | /* End PBXFrameworksBuildPhase section */ 70 | 71 | /* Begin PBXGroup section */ 72 | D4EC7A382136B7EE0034767C = { 73 | isa = PBXGroup; 74 | children = ( 75 | D4EC7A442136B7EE0034767C /* StackBarButtonItem */, 76 | D4EC7A4F2136B7EE0034767C /* StackBarButtonItemTests */, 77 | D4EC7A432136B7EE0034767C /* Products */, 78 | D4EC7A962136BC5C0034767C /* Frameworks */, 79 | ); 80 | sourceTree = ""; 81 | }; 82 | D4EC7A432136B7EE0034767C /* Products */ = { 83 | isa = PBXGroup; 84 | children = ( 85 | D4EC7A6D2136B8AE0034767C /* StackBarButtonItem.framework */, 86 | 314AF9392146666B0008202E /* StackBarButtonItemTests-iOS.xctest */, 87 | ); 88 | name = Products; 89 | sourceTree = ""; 90 | }; 91 | D4EC7A442136B7EE0034767C /* StackBarButtonItem */ = { 92 | isa = PBXGroup; 93 | children = ( 94 | D4EC7A5D2136B7F80034767C /* Source */, 95 | D4EC7A5C2136B7F30034767C /* Resource */, 96 | D4EC7A452136B7EE0034767C /* StackBarButtonItem.h */, 97 | ); 98 | path = StackBarButtonItem; 99 | sourceTree = ""; 100 | }; 101 | D4EC7A4F2136B7EE0034767C /* StackBarButtonItemTests */ = { 102 | isa = PBXGroup; 103 | children = ( 104 | 314AF92F214665D60008202E /* Info-iOS.plist */, 105 | D4EC7A502136B7EE0034767C /* StackBarButtonItemTests.swift */, 106 | ); 107 | path = StackBarButtonItemTests; 108 | sourceTree = ""; 109 | }; 110 | D4EC7A5C2136B7F30034767C /* Resource */ = { 111 | isa = PBXGroup; 112 | children = ( 113 | D4EC7A632136B8100034767C /* Info-iOS.plist */, 114 | ); 115 | path = Resource; 116 | sourceTree = ""; 117 | }; 118 | D4EC7A5D2136B7F80034767C /* Source */ = { 119 | isa = PBXGroup; 120 | children = ( 121 | 314AF9652146783F0008202E /* DeviceExtension.swift */, 122 | D4EC7A5E2136B8070034767C /* StackBarButtonItem.swift */, 123 | 313C7CEF217B7660003B50D1 /* StackViewExtension.swift */, 124 | 31658C73217B0AEF00FD3E18 /* UINavigationItem+StackBarButtonItem.swift */, 125 | ); 126 | path = Source; 127 | sourceTree = ""; 128 | }; 129 | D4EC7A962136BC5C0034767C /* Frameworks */ = { 130 | isa = PBXGroup; 131 | children = ( 132 | 3176E4BC2305411300CB14B0 /* RxRelay.framework */, 133 | D4EC7A972136BC5C0034767C /* NSObject_Rx.framework */, 134 | D4EC7A982136BC5C0034767C /* RxBlocking.framework */, 135 | D4EC7A992136BC5C0034767C /* RxCocoa.framework */, 136 | D4EC7A9B2136BC5C0034767C /* RxSwift.framework */, 137 | D4EC7A9A2136BC5C0034767C /* RxTest.framework */, 138 | ); 139 | name = Frameworks; 140 | sourceTree = ""; 141 | }; 142 | /* End PBXGroup section */ 143 | 144 | /* Begin PBXHeadersBuildPhase section */ 145 | D4EC7A6A2136B8AE0034767C /* Headers */ = { 146 | isa = PBXHeadersBuildPhase; 147 | buildActionMask = 2147483647; 148 | files = ( 149 | ); 150 | runOnlyForDeploymentPostprocessing = 0; 151 | }; 152 | /* End PBXHeadersBuildPhase section */ 153 | 154 | /* Begin PBXNativeTarget section */ 155 | 314AF9382146666B0008202E /* StackBarButtonItemTests-iOS */ = { 156 | isa = PBXNativeTarget; 157 | buildConfigurationList = 314AF9412146666C0008202E /* Build configuration list for PBXNativeTarget "StackBarButtonItemTests-iOS" */; 158 | buildPhases = ( 159 | 314AF9352146666B0008202E /* Sources */, 160 | 314AF9362146666B0008202E /* Frameworks */, 161 | 314AF9372146666B0008202E /* Resources */, 162 | ); 163 | buildRules = ( 164 | ); 165 | dependencies = ( 166 | 314AF9402146666C0008202E /* PBXTargetDependency */, 167 | ); 168 | name = "StackBarButtonItemTests-iOS"; 169 | productName = "StackBarButtonItemTests-iOS"; 170 | productReference = 314AF9392146666B0008202E /* StackBarButtonItemTests-iOS.xctest */; 171 | productType = "com.apple.product-type.bundle.unit-test"; 172 | }; 173 | D4EC7A6C2136B8AE0034767C /* StackBarButtonItem-iOS */ = { 174 | isa = PBXNativeTarget; 175 | buildConfigurationList = D4EC7A722136B8AE0034767C /* Build configuration list for PBXNativeTarget "StackBarButtonItem-iOS" */; 176 | buildPhases = ( 177 | D4EC7A682136B8AE0034767C /* Sources */, 178 | D4EC7A692136B8AE0034767C /* Frameworks */, 179 | D4EC7A6A2136B8AE0034767C /* Headers */, 180 | D4EC7A6B2136B8AE0034767C /* Resources */, 181 | D4EC7AA22136BC6B0034767C /* ShellScript */, 182 | ); 183 | buildRules = ( 184 | ); 185 | dependencies = ( 186 | ); 187 | name = "StackBarButtonItem-iOS"; 188 | productName = "StackBarButtonItem-iOS"; 189 | productReference = D4EC7A6D2136B8AE0034767C /* StackBarButtonItem.framework */; 190 | productType = "com.apple.product-type.framework"; 191 | }; 192 | /* End PBXNativeTarget section */ 193 | 194 | /* Begin PBXProject section */ 195 | D4EC7A392136B7EE0034767C /* Project object */ = { 196 | isa = PBXProject; 197 | attributes = { 198 | LastSwiftUpdateCheck = 0940; 199 | LastUpgradeCheck = 0940; 200 | ORGANIZATIONNAME = "中澤 郁斗"; 201 | TargetAttributes = { 202 | 314AF9382146666B0008202E = { 203 | CreatedOnToolsVersion = 9.4.1; 204 | LastSwiftMigration = 1000; 205 | }; 206 | D4EC7A6C2136B8AE0034767C = { 207 | CreatedOnToolsVersion = 9.4.1; 208 | LastSwiftMigration = 1000; 209 | }; 210 | }; 211 | }; 212 | buildConfigurationList = D4EC7A3C2136B7EE0034767C /* Build configuration list for PBXProject "StackBarButtonItem" */; 213 | compatibilityVersion = "Xcode 9.3"; 214 | developmentRegion = en; 215 | hasScannedForEncodings = 0; 216 | knownRegions = ( 217 | en, 218 | Base, 219 | ); 220 | mainGroup = D4EC7A382136B7EE0034767C; 221 | productRefGroup = D4EC7A432136B7EE0034767C /* Products */; 222 | projectDirPath = ""; 223 | projectRoot = ""; 224 | targets = ( 225 | D4EC7A6C2136B8AE0034767C /* StackBarButtonItem-iOS */, 226 | 314AF9382146666B0008202E /* StackBarButtonItemTests-iOS */, 227 | ); 228 | }; 229 | /* End PBXProject section */ 230 | 231 | /* Begin PBXResourcesBuildPhase section */ 232 | 314AF9372146666B0008202E /* Resources */ = { 233 | isa = PBXResourcesBuildPhase; 234 | buildActionMask = 2147483647; 235 | files = ( 236 | ); 237 | runOnlyForDeploymentPostprocessing = 0; 238 | }; 239 | D4EC7A6B2136B8AE0034767C /* Resources */ = { 240 | isa = PBXResourcesBuildPhase; 241 | buildActionMask = 2147483647; 242 | files = ( 243 | ); 244 | runOnlyForDeploymentPostprocessing = 0; 245 | }; 246 | /* End PBXResourcesBuildPhase section */ 247 | 248 | /* Begin PBXShellScriptBuildPhase section */ 249 | D4EC7AA22136BC6B0034767C /* ShellScript */ = { 250 | isa = PBXShellScriptBuildPhase; 251 | buildActionMask = 2147483647; 252 | files = ( 253 | ); 254 | inputPaths = ( 255 | "$(SRCROOT)/Carthage/Build/iOS/RxSwift.framework", 256 | "$(SRCROOT)/Carthage/Build/iOS/RxCocoa.framework", 257 | "$(SRCROOT)/Carthage/Build/iOS/RxRelay.framework", 258 | ); 259 | outputPaths = ( 260 | ); 261 | runOnlyForDeploymentPostprocessing = 0; 262 | shellPath = /bin/sh; 263 | shellScript = "/usr/local/bin/carthage copy-frameworks\n"; 264 | }; 265 | /* End PBXShellScriptBuildPhase section */ 266 | 267 | /* Begin PBXSourcesBuildPhase section */ 268 | 314AF9352146666B0008202E /* Sources */ = { 269 | isa = PBXSourcesBuildPhase; 270 | buildActionMask = 2147483647; 271 | files = ( 272 | 314AF962214666F70008202E /* StackBarButtonItemTests.swift in Sources */, 273 | ); 274 | runOnlyForDeploymentPostprocessing = 0; 275 | }; 276 | D4EC7A682136B8AE0034767C /* Sources */ = { 277 | isa = PBXSourcesBuildPhase; 278 | buildActionMask = 2147483647; 279 | files = ( 280 | 31658C74217B0AEF00FD3E18 /* UINavigationItem+StackBarButtonItem.swift in Sources */, 281 | 313C7CF0217B7660003B50D1 /* StackViewExtension.swift in Sources */, 282 | D4EC7A912136BA8F0034767C /* StackBarButtonItem.swift in Sources */, 283 | 314AF9662146783F0008202E /* DeviceExtension.swift in Sources */, 284 | ); 285 | runOnlyForDeploymentPostprocessing = 0; 286 | }; 287 | /* End PBXSourcesBuildPhase section */ 288 | 289 | /* Begin PBXTargetDependency section */ 290 | 314AF9402146666C0008202E /* PBXTargetDependency */ = { 291 | isa = PBXTargetDependency; 292 | target = D4EC7A6C2136B8AE0034767C /* StackBarButtonItem-iOS */; 293 | targetProxy = 314AF93F2146666C0008202E /* PBXContainerItemProxy */; 294 | }; 295 | /* End PBXTargetDependency section */ 296 | 297 | /* Begin XCBuildConfiguration section */ 298 | 314AF9422146666C0008202E /* Debug */ = { 299 | isa = XCBuildConfiguration; 300 | buildSettings = { 301 | CODE_SIGN_STYLE = Automatic; 302 | DEVELOPMENT_TEAM = E5RDJ83DDA; 303 | INFOPLIST_FILE = "StackBarButtonItemTests/info-IOS.plist"; 304 | IPHONEOS_DEPLOYMENT_TARGET = 11.4; 305 | LD_RUNPATH_SEARCH_PATHS = ( 306 | "$(inherited)", 307 | "@executable_path/Frameworks", 308 | "@loader_path/Frameworks", 309 | ); 310 | PRODUCT_BUNDLE_IDENTIFIER = "com.funzin.StackBarButtonItemTests-iOS"; 311 | PRODUCT_NAME = "$(TARGET_NAME)"; 312 | SWIFT_VERSION = 5.0; 313 | TARGETED_DEVICE_FAMILY = "1,2"; 314 | }; 315 | name = Debug; 316 | }; 317 | 314AF9432146666C0008202E /* Release */ = { 318 | isa = XCBuildConfiguration; 319 | buildSettings = { 320 | CODE_SIGN_STYLE = Automatic; 321 | DEVELOPMENT_TEAM = E5RDJ83DDA; 322 | INFOPLIST_FILE = "StackBarButtonItemTests/info-IOS.plist"; 323 | IPHONEOS_DEPLOYMENT_TARGET = 11.4; 324 | LD_RUNPATH_SEARCH_PATHS = ( 325 | "$(inherited)", 326 | "@executable_path/Frameworks", 327 | "@loader_path/Frameworks", 328 | ); 329 | PRODUCT_BUNDLE_IDENTIFIER = "com.funzin.StackBarButtonItemTests-iOS"; 330 | PRODUCT_NAME = "$(TARGET_NAME)"; 331 | SWIFT_VERSION = 5.0; 332 | TARGETED_DEVICE_FAMILY = "1,2"; 333 | }; 334 | name = Release; 335 | }; 336 | D4EC7A542136B7EE0034767C /* Debug */ = { 337 | isa = XCBuildConfiguration; 338 | buildSettings = { 339 | ALWAYS_SEARCH_USER_PATHS = NO; 340 | CLANG_ANALYZER_NONNULL = YES; 341 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 342 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 343 | CLANG_CXX_LIBRARY = "libc++"; 344 | CLANG_ENABLE_MODULES = YES; 345 | CLANG_ENABLE_OBJC_ARC = YES; 346 | CLANG_ENABLE_OBJC_WEAK = YES; 347 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 348 | CLANG_WARN_BOOL_CONVERSION = YES; 349 | CLANG_WARN_COMMA = YES; 350 | CLANG_WARN_CONSTANT_CONVERSION = YES; 351 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 352 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 353 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 354 | CLANG_WARN_EMPTY_BODY = YES; 355 | CLANG_WARN_ENUM_CONVERSION = YES; 356 | CLANG_WARN_INFINITE_RECURSION = YES; 357 | CLANG_WARN_INT_CONVERSION = YES; 358 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 359 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 360 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 361 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 362 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 363 | CLANG_WARN_STRICT_PROTOTYPES = YES; 364 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 365 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 366 | CLANG_WARN_UNREACHABLE_CODE = YES; 367 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 368 | CODE_SIGN_IDENTITY = "iPhone Developer"; 369 | COPY_PHASE_STRIP = NO; 370 | CURRENT_PROJECT_VERSION = 1; 371 | DEBUG_INFORMATION_FORMAT = dwarf; 372 | ENABLE_STRICT_OBJC_MSGSEND = YES; 373 | ENABLE_TESTABILITY = YES; 374 | GCC_C_LANGUAGE_STANDARD = gnu11; 375 | GCC_DYNAMIC_NO_PIC = NO; 376 | GCC_NO_COMMON_BLOCKS = YES; 377 | GCC_OPTIMIZATION_LEVEL = 0; 378 | GCC_PREPROCESSOR_DEFINITIONS = ( 379 | "DEBUG=1", 380 | "$(inherited)", 381 | ); 382 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 383 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 384 | GCC_WARN_UNDECLARED_SELECTOR = YES; 385 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 386 | GCC_WARN_UNUSED_FUNCTION = YES; 387 | GCC_WARN_UNUSED_VARIABLE = YES; 388 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 389 | MTL_ENABLE_DEBUG_INFO = YES; 390 | ONLY_ACTIVE_ARCH = YES; 391 | SDKROOT = iphoneos; 392 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 393 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 394 | VERSIONING_SYSTEM = "apple-generic"; 395 | VERSION_INFO_PREFIX = ""; 396 | }; 397 | name = Debug; 398 | }; 399 | D4EC7A552136B7EE0034767C /* Release */ = { 400 | isa = XCBuildConfiguration; 401 | buildSettings = { 402 | ALWAYS_SEARCH_USER_PATHS = NO; 403 | CLANG_ANALYZER_NONNULL = YES; 404 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 405 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 406 | CLANG_CXX_LIBRARY = "libc++"; 407 | CLANG_ENABLE_MODULES = YES; 408 | CLANG_ENABLE_OBJC_ARC = YES; 409 | CLANG_ENABLE_OBJC_WEAK = YES; 410 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 411 | CLANG_WARN_BOOL_CONVERSION = YES; 412 | CLANG_WARN_COMMA = YES; 413 | CLANG_WARN_CONSTANT_CONVERSION = YES; 414 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 415 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 416 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 417 | CLANG_WARN_EMPTY_BODY = YES; 418 | CLANG_WARN_ENUM_CONVERSION = YES; 419 | CLANG_WARN_INFINITE_RECURSION = YES; 420 | CLANG_WARN_INT_CONVERSION = YES; 421 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 422 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 423 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 424 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 425 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 426 | CLANG_WARN_STRICT_PROTOTYPES = YES; 427 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 428 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 429 | CLANG_WARN_UNREACHABLE_CODE = YES; 430 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 431 | CODE_SIGN_IDENTITY = "iPhone Developer"; 432 | COPY_PHASE_STRIP = NO; 433 | CURRENT_PROJECT_VERSION = 1; 434 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 435 | ENABLE_NS_ASSERTIONS = NO; 436 | ENABLE_STRICT_OBJC_MSGSEND = YES; 437 | GCC_C_LANGUAGE_STANDARD = gnu11; 438 | GCC_NO_COMMON_BLOCKS = YES; 439 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 440 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 441 | GCC_WARN_UNDECLARED_SELECTOR = YES; 442 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 443 | GCC_WARN_UNUSED_FUNCTION = YES; 444 | GCC_WARN_UNUSED_VARIABLE = YES; 445 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 446 | MTL_ENABLE_DEBUG_INFO = NO; 447 | SDKROOT = iphoneos; 448 | SWIFT_COMPILATION_MODE = wholemodule; 449 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 450 | VALIDATE_PRODUCT = YES; 451 | VERSIONING_SYSTEM = "apple-generic"; 452 | VERSION_INFO_PREFIX = ""; 453 | }; 454 | name = Release; 455 | }; 456 | D4EC7A732136B8AE0034767C /* Debug */ = { 457 | isa = XCBuildConfiguration; 458 | buildSettings = { 459 | CODE_SIGN_IDENTITY = ""; 460 | CODE_SIGN_STYLE = Manual; 461 | DEFINES_MODULE = YES; 462 | DEVELOPMENT_TEAM = ""; 463 | DYLIB_COMPATIBILITY_VERSION = 1; 464 | DYLIB_CURRENT_VERSION = 1; 465 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 466 | FRAMEWORK_SEARCH_PATHS = ( 467 | "$(inherited)", 468 | "$(PROJECT_DIR)/Carthage/Build/iOS", 469 | ); 470 | INFOPLIST_FILE = "$(SRCROOT)/StackBarButtonItem/Resource/Info-iOS.plist"; 471 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 472 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 473 | LD_RUNPATH_SEARCH_PATHS = ( 474 | "$(inherited)", 475 | "@executable_path/Frameworks", 476 | "@loader_path/Frameworks", 477 | ); 478 | PRODUCT_BUNDLE_IDENTIFIER = "com.funzin.StackBarButtonItem-iOS"; 479 | PRODUCT_NAME = "$(PROJECT_NAME)"; 480 | PROVISIONING_PROFILE_SPECIFIER = ""; 481 | SKIP_INSTALL = YES; 482 | SWIFT_VERSION = 5.0; 483 | TARGETED_DEVICE_FAMILY = "1,2"; 484 | }; 485 | name = Debug; 486 | }; 487 | D4EC7A742136B8AE0034767C /* Release */ = { 488 | isa = XCBuildConfiguration; 489 | buildSettings = { 490 | CODE_SIGN_IDENTITY = ""; 491 | CODE_SIGN_STYLE = Manual; 492 | DEFINES_MODULE = YES; 493 | DEVELOPMENT_TEAM = ""; 494 | DYLIB_COMPATIBILITY_VERSION = 1; 495 | DYLIB_CURRENT_VERSION = 1; 496 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 497 | FRAMEWORK_SEARCH_PATHS = ( 498 | "$(inherited)", 499 | "$(PROJECT_DIR)/Carthage/Build/iOS", 500 | ); 501 | INFOPLIST_FILE = "$(SRCROOT)/StackBarButtonItem/Resource/Info-iOS.plist"; 502 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 503 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 504 | LD_RUNPATH_SEARCH_PATHS = ( 505 | "$(inherited)", 506 | "@executable_path/Frameworks", 507 | "@loader_path/Frameworks", 508 | ); 509 | PRODUCT_BUNDLE_IDENTIFIER = "com.funzin.StackBarButtonItem-iOS"; 510 | PRODUCT_NAME = "$(PROJECT_NAME)"; 511 | PROVISIONING_PROFILE_SPECIFIER = ""; 512 | SKIP_INSTALL = YES; 513 | SWIFT_VERSION = 5.0; 514 | TARGETED_DEVICE_FAMILY = "1,2"; 515 | }; 516 | name = Release; 517 | }; 518 | /* End XCBuildConfiguration section */ 519 | 520 | /* Begin XCConfigurationList section */ 521 | 314AF9412146666C0008202E /* Build configuration list for PBXNativeTarget "StackBarButtonItemTests-iOS" */ = { 522 | isa = XCConfigurationList; 523 | buildConfigurations = ( 524 | 314AF9422146666C0008202E /* Debug */, 525 | 314AF9432146666C0008202E /* Release */, 526 | ); 527 | defaultConfigurationIsVisible = 0; 528 | defaultConfigurationName = Release; 529 | }; 530 | D4EC7A3C2136B7EE0034767C /* Build configuration list for PBXProject "StackBarButtonItem" */ = { 531 | isa = XCConfigurationList; 532 | buildConfigurations = ( 533 | D4EC7A542136B7EE0034767C /* Debug */, 534 | D4EC7A552136B7EE0034767C /* Release */, 535 | ); 536 | defaultConfigurationIsVisible = 0; 537 | defaultConfigurationName = Release; 538 | }; 539 | D4EC7A722136B8AE0034767C /* Build configuration list for PBXNativeTarget "StackBarButtonItem-iOS" */ = { 540 | isa = XCConfigurationList; 541 | buildConfigurations = ( 542 | D4EC7A732136B8AE0034767C /* Debug */, 543 | D4EC7A742136B8AE0034767C /* Release */, 544 | ); 545 | defaultConfigurationIsVisible = 0; 546 | defaultConfigurationName = Release; 547 | }; 548 | /* End XCConfigurationList section */ 549 | }; 550 | rootObject = D4EC7A392136B7EE0034767C /* Project object */; 551 | } 552 | -------------------------------------------------------------------------------- /StackBarButtonItem.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /StackBarButtonItem.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /StackBarButtonItem.xcodeproj/xcshareddata/xcschemes/StackBarButtonItem-iOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 34 | 40 | 41 | 42 | 43 | 44 | 50 | 51 | 52 | 53 | 54 | 55 | 65 | 66 | 72 | 73 | 74 | 75 | 76 | 77 | 83 | 84 | 90 | 91 | 92 | 93 | 95 | 96 | 99 | 100 | 101 | -------------------------------------------------------------------------------- /StackBarButtonItem.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /StackBarButtonItem.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /StackBarButtonItem/Resource/Info-iOS.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleDisplayName 8 | StackBarButtonItem 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | UISupportedInterfaceOrientations~ipad 40 | 41 | UIInterfaceOrientationPortrait 42 | UIInterfaceOrientationPortraitUpsideDown 43 | UIInterfaceOrientationLandscapeLeft 44 | UIInterfaceOrientationLandscapeRight 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /StackBarButtonItem/Source/DeviceExtension.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import UIKit 3 | 4 | extension UIDevice { 5 | var isPhone: Bool { 6 | return self.userInterfaceIdiom == .phone 7 | } 8 | 9 | var isPad: Bool { 10 | return self.userInterfaceIdiom == .pad 11 | } 12 | 13 | var isPlus: Bool { 14 | if isPhone { 15 | let height = UIScreen.main.nativeBounds.height 16 | if height == 1920 || height == 2208 { 17 | return true 18 | } 19 | } 20 | return false 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /StackBarButtonItem/Source/StackBarButtonItem.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import RxSwift 3 | import RxCocoa 4 | 5 | public final class StackBarButtonItem { 6 | /// NavigationBarButtonItem Position 7 | /// 8 | /// - right: 9 | /// - left: 10 | enum BarButtonPosition { 11 | case right 12 | case left 13 | } 14 | 15 | /// dispose variable 16 | private var compositeDisposable = CompositeDisposable() 17 | private let disposeBag = DisposeBag() 18 | 19 | /// use in navigation margin setting 20 | private let marginItem: UIBarButtonItem = UIBarButtonItem(barButtonSystemItem: .fixedSpace, target: nil, action: nil) 21 | 22 | private weak var navigationItem: UINavigationItem? 23 | private let position: BarButtonPosition 24 | 25 | init(navigationItem: UINavigationItem, position: BarButtonPosition) { 26 | self.navigationItem = navigationItem 27 | self.position = position 28 | } 29 | } 30 | 31 | // MARK: public method 32 | public extension StackBarButtonItem { 33 | 34 | /// Set stackView on the right or left side of the navigation bar 35 | /// 36 | /// 37 | /// - Parameters: 38 | /// - views: An array of views to display on the right or left side of the navigation bar 39 | /// - spacing: Space value between view and view 40 | /// - margin: Margin from right or left end of naigationBar 41 | /// - reversed: Switch view order 42 | /// - animated: Animation flag 43 | func setStackBarButtonItems(views: [UIView], spacing: CGFloat = 0, margin: CGFloat = 0, reversed: Bool = false, animated: Bool = false) { 44 | disposeAll() 45 | 46 | var items: [UIBarButtonItem] = [] 47 | if !views.isEmpty { 48 | items = configureItems(views: views, spacing: spacing, margin: margin, reversed: reversed, animated: animated) 49 | } 50 | 51 | switch self.position { 52 | case .right: 53 | self.navigationItem?.setRightBarButtonItems(items, animated: animated) 54 | case .left: 55 | self.navigationItem?.setLeftBarButtonItems(items, animated: animated) 56 | } 57 | } 58 | } 59 | 60 | // MARK: private method 61 | private extension StackBarButtonItem { 62 | 63 | /// compositeDisposable dispose and assign CompositeDisposable 64 | func disposeAll() { 65 | if compositeDisposable.count != 0 { 66 | compositeDisposable.dispose() 67 | compositeDisposable = CompositeDisposable() 68 | } 69 | } 70 | 71 | func addDisposable(_ disposable: Disposable) { 72 | _ = compositeDisposable.insert(disposable) 73 | disposable.disposed(by: disposeBag) 74 | } 75 | 76 | /// Configure UIBarButtonItems 77 | /// 78 | /// 79 | /// - Parameters: 80 | /// - views: An array of views to display on the right or left side of the navigation bar 81 | /// - spacing: Space value between view and view 82 | /// - margin: Margin from right or left end of naigationBar 83 | /// - reversed: Switch view order 84 | /// - animated: Animation flag 85 | /// - Returns: configured items 86 | func configureItems(views: [UIView], spacing: CGFloat = 0, margin: CGFloat = 0, reversed: Bool = false, animated: Bool = false) -> [UIBarButtonItem] { 87 | let views = reversed ? views.reversed(): views 88 | 89 | let baseStackView = createBaseStackView(barButtonPosition: self.position, views: views, spacing: spacing, margin: margin) 90 | let items = convertIntoItems(baseStackView) 91 | 92 | congifureNavigationMargin(barButtonPosition: self.position, childStackView: baseStackView) 93 | return items 94 | } 95 | 96 | /// Create BaseStackView to embed in BarButtonItem. baseStackView includes childStackView(views and spacing) and margin view 97 | /// - Parameters: 98 | /// - barButtonPosition: right or left 99 | /// - views: An array of views to display on the right or left side of the navigation bar 100 | /// - spacing: Space value between view and view 101 | /// - margin: Margin from the right or left end of navigationBar 102 | /// - Returns: StackView which has finished setting such as margin and space 103 | func createBaseStackView(barButtonPosition: BarButtonPosition, views: [UIView], spacing: CGFloat = 0, margin: CGFloat = 0) -> UIStackView { 104 | let childStackView = createChildStackView(views: views, spacing: spacing) 105 | let baseStackView = UIStackView(arrangedSubviews: [childStackView]) 106 | 107 | baseStackView.configure(spacing: 0) 108 | baseStackView.addMarginView(barButtonPosition: self.position, margin: margin) 109 | baseStackView.updateFrameSize() 110 | 111 | return baseStackView 112 | } 113 | 114 | /// Create childStackView. childStackView includes views and spacing 115 | /// - Parameters: 116 | /// - views: An array of views to display on the right or left side of the navigation bar 117 | /// - spacing: Space value between view and view 118 | /// - Returns: StackView which has finished setting such as spacing 119 | func createChildStackView(views: [UIView], spacing: CGFloat = 0) -> UIStackView { 120 | let childStackView = UIStackView(arrangedSubviews: views) 121 | childStackView.configure(spacing: spacing) 122 | childStackView.updateFrameSize() 123 | 124 | return childStackView 125 | } 126 | 127 | /// Configure navigationMargin 128 | /// 129 | /// - Parameters: 130 | /// - barButtonPosition: left or rihgt 131 | /// - childStackView: StackView for embedding in BarButtonItem 132 | func congifureNavigationMargin(barButtonPosition: BarButtonPosition, childStackView: UIStackView) { 133 | if #available(iOS 11, *) { 134 | hideExtraMarginView(barButtonPosition, childStackView) 135 | } else { 136 | configureMinusMargin() 137 | } 138 | } 139 | 140 | /// Convert stackView(customView) into BarButtonItem 141 | /// 142 | /// - Parameter stackView: CustomView of BarButtonItem 143 | /// - Returns: An array of UIBarButtonItem with marginItem in case of iOS 10 or less 144 | func convertIntoItems(_ stackView: UIStackView) -> [UIBarButtonItem] { 145 | let items: [UIBarButtonItem] 146 | if #available(iOS 11, *) { 147 | items = [UIBarButtonItem(customView: stackView)] 148 | } else { 149 | items = [marginItem, UIBarButtonItem(customView: stackView)] 150 | } 151 | return items 152 | } 153 | } 154 | 155 | // MARK: iOS11 or later private method 156 | @available(iOS 11, *) 157 | private extension StackBarButtonItem { 158 | 159 | /// Hide extra margin view 160 | /// 161 | /// - Parameters: 162 | /// - barButtonPosition: right or left 163 | /// - childStackView: StackView for embedding in BarButtonItem 164 | func hideExtraMarginView(_ barButtonPosition: BarButtonPosition, _ childStackView: UIStackView) { 165 | 166 | let disposable = childStackView.rx.methodInvoked(#selector(UIView.didMoveToSuperview)) 167 | .observeOn(ConcurrentMainScheduler.instance) 168 | .flatMap { [weak childStackView] _ -> Observable in 169 | childStackView.flatMap { ($0.superview as? UIStackView).map(Observable.just) } ?? .empty() 170 | } 171 | .do(onNext: { (superStackView) in 172 | // Add constraint 173 | guard let guide = superStackView.superview?.safeAreaLayoutGuide else { return } 174 | switch barButtonPosition { 175 | case .right: 176 | superStackView.rightAnchor.constraint(equalTo: guide.rightAnchor).isActive = true 177 | case .left: 178 | superStackView.leftAnchor.constraint(equalTo: guide.leftAnchor).isActive = true 179 | } 180 | }) 181 | .flatMap({ [weak self] (superStackView) -> Observable in 182 | guard let me = self else { return .empty() } 183 | return me.didAddSubView(superStackView) 184 | }) 185 | .subscribe(onNext: { (superStackView) in 186 | // hide all views except UIStackView 187 | (superStackView.arrangedSubviews + superStackView.subviews) 188 | .filter {type(of: $0) != UIStackView.self } 189 | .forEach { $0.isHidden = true } 190 | }) 191 | 192 | addDisposable(disposable) 193 | } 194 | 195 | /// Check didAddSubView timing 196 | /// 197 | /// - Parameter stackView: superView of childStackView 198 | /// - Returns: An Observable sequence 199 | func didAddSubView(_ stackView: UIStackView) -> Observable { 200 | return stackView.rx.methodInvoked(#selector(UIStackView.didAddSubview(_:))) 201 | .map { _ in stackView } 202 | } 203 | } 204 | 205 | // MARK: iOS10 or less private method 206 | @available(iOS, introduced: 9.0, obsoleted: 11.0) 207 | private extension StackBarButtonItem { 208 | 209 | /// Configure margin width 210 | func configureMinusMargin() { 211 | guard let rootVC = UIApplication.shared.delegate?.window??.rootViewController?.children.first else { return } 212 | 213 | // observe viewWillLayoutSubviews(transition) 214 | let disposable = rootVC.rx.methodInvoked(#selector(UIViewController.viewWillLayoutSubviews)) 215 | .observeOn(ConcurrentMainScheduler.instance) 216 | .subscribe(onNext: { [weak self] (_) in 217 | guard let me = self else { return } 218 | 219 | // configure margin 220 | me.marginItem.width = me.minusMargin(rootVC.traitCollection) 221 | }) 222 | 223 | addDisposable(disposable) 224 | } 225 | 226 | /// Minus margin width in case of iOS 10 or or less 227 | /// 228 | /// - Parameter traitCollection: Use for iPhone Orientation 229 | /// - Returns: Appropriate minus margin width 230 | func minusMargin(_ traitCollection: UITraitCollection) -> CGFloat { 231 | if UIDevice.current.isPad || UIDevice.current.isPlus { 232 | return -20 233 | } 234 | 235 | // iPhone 236 | return traitCollection.verticalSizeClass == .regular ? -16: -20 237 | } 238 | } 239 | -------------------------------------------------------------------------------- /StackBarButtonItem/Source/StackViewExtension.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | extension UIStackView { 4 | func configure(spacing: CGFloat = 0) { 5 | self.axis = .horizontal 6 | self.alignment = .center 7 | self.distribution = .fill 8 | self.spacing = spacing 9 | } 10 | 11 | func updateFrameSize() { 12 | let spaceWidth = CGFloat(max(self.arrangedSubviews.count - 1, 0)) * self.spacing 13 | let width = self.arrangedSubviews.reduce(CGFloat(0), { $0 + $1.frame.size.width }) + spaceWidth 14 | let height = self.arrangedSubviews.reduce(CGFloat(0), { max($0, $1.frame.size.height) }) 15 | self.frame.size = CGSize(width: width, height: height) 16 | } 17 | 18 | func addMarginView(barButtonPosition: StackBarButtonItem.BarButtonPosition, margin: CGFloat = 0) { 19 | if margin > 0 { 20 | let marginView = UIView(frame: CGRect(x: 0, y: 0, width: margin, height: 0)) 21 | marginView.widthAnchor.constraint(equalToConstant: margin).isActive = true 22 | 23 | switch barButtonPosition { 24 | case .left: 25 | self.insertArrangedSubview(marginView, at: 0) 26 | case .right: 27 | self.addArrangedSubview(marginView) 28 | } 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /StackBarButtonItem/Source/UINavigationItem+StackBarButtonItem.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | private let _rightAssociatedKey = UnsafeMutablePointer.allocate(capacity: 1) 4 | private let _leftAssociatedKey = UnsafeMutablePointer.allocate(capacity: 1) 5 | 6 | extension UINavigationItem { 7 | public var right: StackBarButtonItem { 8 | guard let stackBarButtonItem = objc_getAssociatedObject(self, _rightAssociatedKey) as? StackBarButtonItem else { 9 | let stackBarButtonItem = StackBarButtonItem(navigationItem: self, position: .right) 10 | objc_setAssociatedObject(self, _rightAssociatedKey, stackBarButtonItem, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) 11 | return stackBarButtonItem 12 | } 13 | return stackBarButtonItem 14 | } 15 | 16 | public var left: StackBarButtonItem { 17 | guard let stackBarButtonItem = objc_getAssociatedObject(self, _leftAssociatedKey) as? StackBarButtonItem else { 18 | let stackBarButtonItem = StackBarButtonItem(navigationItem: self, position: .left) 19 | objc_setAssociatedObject(self, _leftAssociatedKey, stackBarButtonItem, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) 20 | return stackBarButtonItem 21 | } 22 | return stackBarButtonItem 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /StackBarButtonItem/StackBarButtonItem.h: -------------------------------------------------------------------------------- 1 | // 2 | // StackBarButtonItem.h 3 | // StackBarButtonItem 4 | // 5 | // Created by 中澤 郁斗 on 2018/08/29. 6 | // Copyright © 2018年 中澤 郁斗. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for StackBarButtonItem. 12 | FOUNDATION_EXPORT double StackBarButtonItemVersionNumber; 13 | 14 | //! Project version string for StackBarButtonItem. 15 | FOUNDATION_EXPORT const unsigned char StackBarButtonItemVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | -------------------------------------------------------------------------------- /StackBarButtonItemTests/Info-iOS.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /StackBarButtonItemTests/StackBarButtonItemTests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | @testable import StackBarButtonItem 3 | 4 | class StackBarButtonItemTests: XCTestCase { 5 | 6 | var vc: UIViewController! 7 | 8 | var rightButton1: UIButton! 9 | var rightButton2: UIButton! 10 | 11 | var leftButton1: UIButton! 12 | var leftButton2: UIButton! 13 | 14 | override func setUp() { 15 | super.setUp() 16 | vc = UIViewController() 17 | 18 | rightButton1 = UIButton(frame: CGRect(x: 0, y: 0, width: 44, height: 44)) 19 | rightButton2 = UIButton(frame: CGRect(x: 0, y: 0, width: 44, height: 44)) 20 | leftButton1 = UIButton(frame: CGRect(x: 0, y: 0, width: 44, height: 44)) 21 | leftButton2 = UIButton(frame: CGRect(x: 0, y: 0, width: 44, height: 44)) 22 | 23 | [rightButton1, rightButton2, leftButton1, leftButton2] 24 | .forEach { 25 | $0!.widthAnchor.constraint(equalToConstant: 44).isActive = true 26 | $0!.heightAnchor.constraint(equalToConstant: 44).isActive = true 27 | } 28 | 29 | // Put setup code here. This method is called before the invocation of each test method in the class. 30 | } 31 | 32 | override func tearDown() { 33 | // Put teardown code here. This method is called after the invocation of each test method in the class. 34 | super.tearDown() 35 | } 36 | 37 | func testArrangedSubViewsCount() { 38 | vc.navigationItem.left.setStackBarButtonItems(views: [leftButton1, leftButton2]) 39 | vc.navigationItem.right.setStackBarButtonItems(views: [rightButton1, rightButton2]) 40 | vc.view.layoutIfNeeded() 41 | 42 | guard let rightBaseStackView = vc.navigationItem.rightBarButtonItems?.last?.customView as? UIStackView, 43 | let rightChildStackView = rightBaseStackView.arrangedSubviews.first as? UIStackView, 44 | let leftBaseStackView = vc.navigationItem.leftBarButtonItems?.last?.customView as? UIStackView, 45 | let leftChildStackView = leftBaseStackView.arrangedSubviews.last as? UIStackView else { 46 | XCTFail("Expected stackView is not nil") 47 | return 48 | } 49 | 50 | // baseStackView 51 | XCTAssertTrue(rightBaseStackView.arrangedSubviews.count == 1) 52 | XCTAssertTrue(leftBaseStackView.arrangedSubviews.count == 1) 53 | 54 | // childStackView 55 | XCTAssertTrue(rightChildStackView.arrangedSubviews.count == 2) 56 | XCTAssertTrue(leftChildStackView.arrangedSubviews.count == 2) 57 | } 58 | 59 | func testStackViewSize() { 60 | vc.navigationItem.left.setStackBarButtonItems(views: [leftButton1, leftButton2]) 61 | vc.navigationItem.right.setStackBarButtonItems(views: [rightButton1, rightButton2]) 62 | 63 | guard let rightBaseStackView = vc.navigationItem.rightBarButtonItems?.last?.customView as? UIStackView, 64 | let leftBaseStackView = vc.navigationItem.leftBarButtonItems?.last?.customView as? UIStackView else { 65 | XCTFail("Expected stackView is not nil") 66 | return 67 | } 68 | 69 | let rightSize = rightBaseStackView.frame.size 70 | let leftSize = leftBaseStackView.frame.size 71 | XCTAssertTrue(rightSize == CGSize(width: 88, height: 44)) 72 | XCTAssertTrue(leftSize == CGSize(width: 88, height: 44)) 73 | } 74 | 75 | func testStackViewSpace() { 76 | vc.navigationItem.left.setStackBarButtonItems(views: [leftButton1, leftButton2], spacing: 10) 77 | vc.navigationItem.right.setStackBarButtonItems(views: [rightButton1, rightButton2], spacing: 10) 78 | 79 | guard let rightBaseStackView = vc.navigationItem.rightBarButtonItems?.last?.customView as? UIStackView, 80 | let rightChildStackView = rightBaseStackView.arrangedSubviews.first as? UIStackView, 81 | let leftBaseStackView = vc.navigationItem.leftBarButtonItems?.last?.customView as? UIStackView, 82 | let leftChildStackView = leftBaseStackView.arrangedSubviews.last as? UIStackView else { 83 | XCTFail("Expected stackView is not nil") 84 | return 85 | } 86 | 87 | let rightWidth = rightChildStackView.frame.width 88 | let leftWidth = leftChildStackView.frame.width 89 | 90 | XCTAssertTrue(rightWidth == 98) 91 | XCTAssertTrue(leftWidth == 98) 92 | XCTAssertTrue(rightChildStackView.spacing == 10) 93 | XCTAssertTrue(leftChildStackView.spacing == 10) 94 | } 95 | 96 | func testStackViewMargin() { 97 | vc.navigationItem.left.setStackBarButtonItems(views: [leftButton1, leftButton2], margin: 10) 98 | vc.navigationItem.right.setStackBarButtonItems(views: [rightButton1, rightButton2], margin: 10) 99 | 100 | guard let rightBaseStackView = vc.navigationItem.rightBarButtonItems?.last?.customView as? UIStackView, 101 | let rightChildStackView = rightBaseStackView.arrangedSubviews.first as? UIStackView, 102 | let leftBaseStackView = vc.navigationItem.leftBarButtonItems?.last?.customView as? UIStackView, 103 | let leftChildStackView = leftBaseStackView.arrangedSubviews.last as? UIStackView else { 104 | XCTFail("Expected stackView is not nil") 105 | return 106 | } 107 | 108 | XCTAssertTrue(rightBaseStackView.arrangedSubviews.count == 2) 109 | XCTAssertTrue(rightChildStackView.arrangedSubviews.count == 2) 110 | XCTAssertTrue(rightBaseStackView.frame.width == 98) 111 | XCTAssertTrue(rightChildStackView.frame.width == 88) 112 | 113 | XCTAssertTrue(leftBaseStackView.arrangedSubviews.count == 2) 114 | XCTAssertTrue(leftChildStackView.arrangedSubviews.count == 2) 115 | XCTAssertTrue(leftBaseStackView.frame.width == 98) 116 | XCTAssertTrue(leftChildStackView.frame.width == 88) 117 | } 118 | 119 | func testStackViewMarginAndSapcing() { 120 | vc.navigationItem.left.setStackBarButtonItems(views: [leftButton1, leftButton2], spacing: 20, margin: 10) 121 | vc.navigationItem.right.setStackBarButtonItems(views: [rightButton1, rightButton2], spacing: 20, margin: 10) 122 | 123 | guard let rightBaseStackView = vc.navigationItem.rightBarButtonItems?.last?.customView as? UIStackView, 124 | let rightChildStackView = rightBaseStackView.arrangedSubviews.first as? UIStackView, 125 | let leftBaseStackView = vc.navigationItem.leftBarButtonItems?.last?.customView as? UIStackView, 126 | let leftChildStackView = leftBaseStackView.arrangedSubviews.last as? UIStackView else { 127 | XCTFail("Expected stackView is not nil") 128 | return 129 | } 130 | 131 | XCTAssertTrue(rightBaseStackView.arrangedSubviews.count == 2) 132 | XCTAssertTrue(rightChildStackView.arrangedSubviews.count == 2) 133 | XCTAssertTrue(rightBaseStackView.frame.width == 118) 134 | XCTAssertTrue(rightChildStackView.frame.width == 108) 135 | XCTAssertTrue(rightChildStackView.spacing == 20) 136 | 137 | XCTAssertTrue(leftBaseStackView.arrangedSubviews.count == 2) 138 | XCTAssertTrue(leftChildStackView.arrangedSubviews.count == 2) 139 | XCTAssertTrue(leftBaseStackView.frame.width == 118) 140 | XCTAssertTrue(leftChildStackView.frame.width == 108) 141 | XCTAssertTrue(leftChildStackView.spacing == 20) 142 | 143 | } 144 | 145 | func testStackViewReversed() { 146 | vc.navigationItem.left.setStackBarButtonItems(views: [leftButton1, leftButton2], reversed: true) 147 | vc.navigationItem.right.setStackBarButtonItems(views: [rightButton1, rightButton2], reversed: true) 148 | 149 | guard let rightBaseStackView = vc.navigationItem.rightBarButtonItems?.last?.customView as? UIStackView, 150 | let rightChildStackView = rightBaseStackView.arrangedSubviews.first as? UIStackView, 151 | let leftBaseStackView = vc.navigationItem.leftBarButtonItems?.last?.customView as? UIStackView, 152 | let leftChildStackView = leftBaseStackView.arrangedSubviews.last as? UIStackView else { 153 | XCTFail("Expected stackView is not nil") 154 | return 155 | } 156 | 157 | XCTAssertTrue(rightChildStackView.arrangedSubviews.reversed() == [rightButton1, rightButton2]) 158 | XCTAssertTrue(leftChildStackView.arrangedSubviews.reversed() == [leftButton1, leftButton2]) 159 | } 160 | 161 | func testStackViewEmpty() { 162 | vc.navigationItem.left.setStackBarButtonItems(views: []) 163 | vc.navigationItem.right.setStackBarButtonItems(views: []) 164 | 165 | guard let rightBarButtonItems = vc.navigationItem.rightBarButtonItems, 166 | let leftBarButtonItems = vc.navigationItem.leftBarButtonItems else { 167 | XCTFail("Expected barButtonItems is not nil") 168 | return 169 | } 170 | 171 | XCTAssertTrue(rightBarButtonItems.isEmpty) 172 | XCTAssertTrue(leftBarButtonItems.isEmpty) 173 | } 174 | } 175 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | comment: 2 | behavior: new 3 | --------------------------------------------------------------------------------